﻿//======================================================================
//
//	Cross-Platform XNA Menu System
//  http://cpxms.codeplex.com/
//
//  All code and content licensed under Microsoft Public License (Ms-PL)	
//
//======================================================================
//
//	File:		GraphicsDeviceService.cs
//
//	Author:		MJP
//
//	Date:		04/12/09
//
//======================================================================

using System;
using System.Collections.Generic;
using System.Threading;

using Microsoft.Xna.Framework.Graphics;

namespace CPXMenuEditor
{
    /// <summary>
    /// Helper class responsible for creating and managing the GraphicsDevice.
    /// Implements IGraphicsDeviceService, so it can be used with ContentManager.
    /// </summary>
    public class GraphicsDeviceService : IGraphicsDeviceService, IDisposable
    {
        private GraphicsDevice graphicsDevice;
        private PresentationParameters parameters;
        private int backBufferWidth = 1280;
        private int backBufferHeight = 720;
        private bool disposed = false;

        // IGraphicsDeviceService events.
        public event EventHandler DeviceCreated;
        public event EventHandler DeviceDisposing;
        public event EventHandler DeviceReset;
        public event EventHandler DeviceResetting;

        /// <summary>
        /// Gets the current graphics device.
        /// </summary>
        public GraphicsDevice GraphicsDevice
        {
            get { return graphicsDevice; }
        }

        public int BackBufferWidth
        {
            get { return backBufferWidth; }
        }

        public int BackBufferHeight
        {
            get { return backBufferHeight; }
        }

        public GraphicsDeviceService(IntPtr windowHandle)
        {
            OnReset();
            
            GraphicsAdapter adapter = GraphicsAdapter.DefaultAdapter;
            DeviceType devType = DeviceType.Hardware;

            graphicsDevice = new GraphicsDevice(adapter,
                                                devType,
                                                windowHandle,
                                                parameters);


            if (DeviceCreated != null)
                DeviceCreated.Invoke(this, EventArgs.Empty);
        }
        

        public void OnReset()
        {
            parameters = new PresentationParameters();

            parameters.BackBufferWidth = backBufferWidth;
            parameters.BackBufferHeight = backBufferHeight;
            parameters.BackBufferFormat = SurfaceFormat.Color;
            parameters.AutoDepthStencilFormat = DepthFormat.Depth24Stencil8;
            parameters.EnableAutoDepthStencil = true;
            parameters.PresentOptions = PresentOptions.None;
            parameters.SwapEffect = SwapEffect.Discard;
            parameters.BackBufferCount = 1;
            parameters.PresentationInterval = PresentInterval.One;
        }


        /// <summary>
        /// Resets the graphics device to whichever is bigger out of the specified
        /// resolution or its current size. This behavior means the device will
        /// demand-grow to the largest of all its GraphicsDeviceControl clients.
        /// </summary>
        public void ResetDevice()
        {
            if (DeviceResetting != null)
                DeviceResetting(this, EventArgs.Empty);

            OnReset();

            graphicsDevice.Reset(parameters);

            if (DeviceReset != null)
                DeviceReset(this, EventArgs.Empty);
        }

        public GraphicsDeviceStatus BeginDraw()
        {
            if (graphicsDevice.GraphicsDeviceStatus == GraphicsDeviceStatus.NotReset)
                ResetDevice();

            return graphicsDevice.GraphicsDeviceStatus;
        }

        public void EndDraw()
        {
            try
            {
                graphicsDevice.Present();
            }
            catch (DeviceLostException)
            {
                // Don't worry about it, we'll catch this next time in BeginDraw
            }
        }

        public void SetBackBufferDimensions(int width, int height)
        {
            if (width == backBufferWidth && height == backBufferHeight)
                return;

            backBufferWidth = width;
            backBufferHeight = height;

            ResetDevice();
        }

        ~GraphicsDeviceService()
        {
            Dispose(false);
        }

        protected void Dispose (bool disposeManagedResources)
        {
            if (disposed)
                return;

            if (disposeManagedResources)
            {
                if (DeviceDisposing != null)
                    DeviceDisposing(this, EventArgs.Empty);

                graphicsDevice.Dispose();
            }
        }

        public void Dispose()
        {
            Dispose(true);

            GC.SuppressFinalize(this);
        }
    }
}
